package com.abc.scholarship.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.abc.scholarship.common.constants.CacheConstant;
import com.abc.scholarship.common.enums.RoleEnum;
import com.abc.scholarship.common.utils.MajorGradeNumUtil;
import com.abc.scholarship.common.utils.RedisUtil;
import com.abc.scholarship.domain.dto.StudentImportDto;
import com.abc.scholarship.domain.dto.UserStudentDTO;
import com.abc.scholarship.domain.entity.*;
import com.abc.scholarship.domain.page.PageDTO;
import com.abc.scholarship.domain.page.PageQuery;
import com.abc.scholarship.domain.vo.resp.ApplyVO;
import com.abc.scholarship.domain.vo.resp.UserQueryVo;
import com.abc.scholarship.domain.vo.resp.UserStudentVO;
import com.abc.scholarship.exception.BusinessException;
import com.abc.scholarship.mapper.ApplyMapper;
import com.abc.scholarship.mapper.MajorGradeNumMapper;
import com.abc.scholarship.mapper.UserMapper;
import com.abc.scholarship.service.*;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.read.listener.PageReadListener;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author jzw
 * @since 2024-07-02
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private CollegeService collegeService;

    @Autowired
    private MajorService majorService;

    @Autowired
    private ClassService classService;

    @Autowired
    private StudentService studentService;

    @Autowired
    private MajorGradeNumService majorGradeNumService;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private ApplyMapper applyMapper;

    private static final ThreadPoolExecutor executor = new ThreadPoolExecutor(
            50, 200, 5, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<>(),
            new ThreadPoolExecutor.CallerRunsPolicy());

    @Override
    @Transactional
    public void importStu(MultipartFile multipartFile) {
        if (Objects.isNull(multipartFile) || multipartFile.isEmpty()) {
            throw new BusinessException("文件为空");
        }

        // 导入数据
        try {
            EasyExcel.read(multipartFile.getInputStream(), StudentImportDto.class,
                    new PageReadListener<StudentImportDto>(this::handleSaveBefore)
            ).sheet().doRead();
        } catch (IOException e) {
            throw new BusinessException("上传出错");
        }
    }

    /**根据用户名查用户
     * @param username
     * @return
     */
    @Override
    public User findUserByUsername(String username) { // 实现这个方法
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("u_account",username);  // 这里的第一个值就是列名
        return baseMapper.selectOne(wrapper);
    }

    @Override
    public IPage<UserStudentVO> queryUser(Page<UserStudentVO> page, UserQueryVo userQueryVo) {
        List<UserStudentVO> records = userMapper.getPage(page, userQueryVo);
        page.setRecords(records);
        return page;
    }

    /**
     * 根据用户id 查询用户
     * @param id
     * @return
     */
    @Override
    public UserStudentVO getUserById(Long id) {
        return userMapper.getUserById(id);
    }

    @Override
    public void addUser(UserStudentDTO userStudentDTO) {
        User user = new User();
        user.setUAccount(userStudentDTO.getUAccount());
        user.setUName(userStudentDTO.getUName());
        user.setAvatar("https://img.picui.cn/free/2024/07/03/6684bc19099b1.png");
        user.setUPassword(getPassword(userStudentDTO.getUAccount()));
        user.setRoleId(userStudentDTO.getRoleId());
        if(userStudentDTO.getSex().equals("男")){
            user.setSex(1);
        }else{
            user.setSex(2);
        }
        baseMapper.insert(user);
        if(user.getRoleId().equals(RoleEnum.STUDENT.getRoleId())){
            Long id = findUserByUsername(userStudentDTO.getUAccount()).getId();
            Student student = new Student();
            student.setUId(id);
            student.setClassId(userStudentDTO.getClassId());
            student.setMajorId(userStudentDTO.getMajorId());
            student.setCollegeId(userStudentDTO.getCollegeId());
            student.setGpa(userStudentDTO.getGpa());
            student.setAddGpa(BigDecimal.valueOf(0.00));
            student.setTotalGpa(userStudentDTO.getGpa());
            student.setClassName(userStudentDTO.getClassName());
            student.setMajorName(userStudentDTO.getMajor());
            student.setCollegeName(userStudentDTO.getCollege());
            student.setUName(userStudentDTO.getUName());
            String majorGradeName = MajorGradeNumUtil.getMajorGrade(userStudentDTO.getClassName());
            // 查询专业年级 人数
            QueryWrapper<MajorGradeNum> wrapper = new QueryWrapper<>();
            wrapper.eq("major_grade",majorGradeName);  // 这里的第一个值就是列名
            MajorGradeNum gradeNum = majorGradeNumService.getOne(wrapper);
            student.setMajorGradeId(gradeNum.getId());
            gradeNum.setNum(gradeNum.getNum()+1);
            majorGradeNumService.updateById(gradeNum);
            studentService.save(student);
        }
    }

    /**
     * 修改用户信息
     * @param userStudentDTO
     */
    @Override
    public void updateUser(UserStudentDTO userStudentDTO) {
        User u = userMapper.getUserById(userStudentDTO.getId());
        u.setUName(userStudentDTO.getUName());
        if(userStudentDTO.getSex().equals("男")){
            u.setSex(1);
        }else {
            u.setSex(2);
        }
        userMapper.updateById(u);
        Long userId = userStudentDTO.getId();
        Student student = studentService.getById(userId);
        student.setUName(userStudentDTO.getUName());
        student.setGpa(userStudentDTO.getGpa());
        LambdaQueryWrapper<Apply> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Apply::getUId,userId).eq(Apply::getYear, LocalDate.now().getYear());
        Apply apply = applyMapper.selectOne(wrapper);
        if(apply!=null){
            apply.setStuGpa(userStudentDTO.getGpa());
            apply.setStuTotalGpa(userStudentDTO.getGpa().add(apply.getStuAddGpa()));
            applyMapper.updateById(apply);
        }
        studentService.updateById(student);
    }

    private void handleSaveBefore(List<StudentImportDto> dataList) {
        List<Clazz> clzzList = new ArrayList<>();
        List<Major> majorList = new ArrayList<>();
        List<College> collegeList = new ArrayList<>();
        Set<MajorGradeNum> majorGradeList = new HashSet<>();
        dataList.forEach(item -> {
            collegeList.add(College.buildFromExcel(item));
            majorList.add(Major.buildFromExcel(item));
            clzzList.add(Clazz.buildFromExcel(item));
            majorGradeList.add(new MajorGradeNum(MajorGradeNumUtil.getMajorGrade(item.getClazz()), 0));
        });
        List<Clazz> classNot = classService.getNotExitByNames(clzzList.stream().map(Clazz::getClassName).collect(Collectors.toList()));
        List<Major> majorNot = majorService.getNotExitByNames(majorList.stream().map(Major::getMajorName).collect(Collectors.toList()));
        List<College> collegeNot = collegeService.getNotExitByNames(collegeList.stream().map(College::getCollegeName).collect(Collectors.toList()));
        List<MajorGradeNum> majorGradeNumNot = majorGradeNumService.getNotExitByNames(majorGradeList.stream().map(MajorGradeNum::getMajorGrade).collect(Collectors.toList()));

        // 批量保存
        classService.saveBatch(classNot);
        majorService.saveBatch(majorNot);
        collegeService.saveBatch(collegeNot);
        majorGradeNumService.saveBatch(majorGradeNumNot);
        Map<String, MajorGradeNum> majorGradeMap = majorGradeNumService.list().stream().collect(Collectors.toMap(MajorGradeNum::getMajorGrade, Function.identity()));

        // 批量保存学生和绩点数据
        dataList.forEach(item -> {
            executor.execute(() -> {
                this.saveStuInfo(item, majorGradeMap);
            });
        });
    }

    public void saveStuInfo(StudentImportDto stuInfo, Map<String, MajorGradeNum> majorGradeMap) {
        try {
            // 正片开始
            College findCollege = collegeService.getOne(new LambdaQueryWrapper<College>().eq(College::getCollegeName, stuInfo.getCollege()));
            Major findMajor = majorService.getOne(new LambdaQueryWrapper<Major>().eq(Major::getMajorName, stuInfo.getMajor()));
            Clazz findClazz = classService.getOne(new LambdaQueryWrapper<Clazz>().eq(Clazz::getClassName, stuInfo.getClazz()));
            // 学生
            User findUser = User.buildFromExcel(stuInfo, getPassword(stuInfo.getUAccount()));
            User user = getOne(new LambdaQueryWrapper<User>().eq(User::getUAccount, stuInfo.getUAccount()));
            if (Objects.isNull(user)) {
                save(findUser);
                // 记录学生数量
                String majorGrade = MajorGradeNumUtil.getMajorGrade(stuInfo.getClazz());
                String redisKey = CacheConstant.getKey(CacheConstant.IMPORT_KEY, majorGrade);
                Boolean lock = redisUtil.lock(redisKey);
                while (!lock) {
                    lock = redisUtil.lock(redisKey);
                }
                redisUtil.unlock(redisKey);
                majorGradeNumService.addStuNum(majorGrade);
            } else {
                findUser.setId(user.getId());
                updateById(findUser);
            }
            // 绩点
            Student buildStudent = Student.buildFromExcel(findClazz, findMajor, findCollege, findUser, stuInfo,
                    majorGradeMap.get(MajorGradeNumUtil.getMajorGrade(findClazz.getClassName())).getId());
            Student student = studentService.getById(findUser.getId());
            if (Objects.isNull(student)) {
                studentService.save(buildStudent);
            } else {
                buildStudent.setUId(student.getUId());
                studentService.updateById(buildStudent);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private String getPassword(String uAccount) {
        return new BCryptPasswordEncoder().encode(uAccount.substring(uAccount.length() - 6));
    }
}
